package com.qfx.demo.shiro;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.qfx.demo.cache.MenuRoleCache;
import com.qfx.demo.vo.SysMenuRole;

@Configuration
public class ShiroConfig {
	
	/**
	 * <h5>功能:自定义realm认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理</h5>
	 * 
	 * @author zhangpj	@date 2018年10月11日
	 * @param hashMatcher
	 * @return 
	 */
	@Bean
	public JwtRealm jwtRealm(){
		return new JwtRealm();
	}
	
	/**
     * <h5>功能:安全管理器</h5>
     * 权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类
	 * 
	 * @param jwtRealm
	 * @return 
	 */
	@Bean
    public DefaultWebSecurityManager securityManager(JwtRealm jwtRealm){
		// 创建安全管理器对象
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        
        // 设置自定义Realm
        securityManager.setRealm(jwtRealm);
        
        // 关闭Shiro自带session
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        
        return securityManager;
    }
	
	/**
     * <h5>功能:自定义权限过滤器</h5>
     * 
     * @param securityManager
     * @return 
     */
    @Bean
	public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 调用我们配置的安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 配置我们的登录请求地址,非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
//        shiroFilterFactoryBean.setLoginUrl("/error/401.html");
        // 设置无权限时跳转的URL
//        shiroFilterFactoryBean.setUnauthorizedUrl("/error/403.html");
        
        // 获取Shiro的默认过滤器
        Map<String, Filter> filter = shiroFilterFactoryBean.getFilters();
        // 将自定义的过滤器 jwt添加到shiroFilterFactoryBean中
        filter.put("jwt", new CustomJwtFilter());
        filter.put("roles", new CustomRolesFilter());
        // 设置过滤器链中的过滤器
        shiroFilterFactoryBean.setFilters(filter);
        
        // ========== 动态加载权限核心部分开始 ==========
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 对静态资源设置匿名访问,从resoutces/static后面开始写
        filterChainDefinitionMap.put("/css/**", "anon");
        // 可匿名访问的地址
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/index.jsp", "anon");
        filterChainDefinitionMap.put("/login/loginPage", "anon");
        filterChainDefinitionMap.put("/login/register", "anon");
        filterChainDefinitionMap.put("/login/login", "anon");
        // 请求 logout.do地址,shiro去清除session
        filterChainDefinitionMap.put("/logout", "logout");
        
        //循环url,逐个添加到section中。section就是filterChainDefinitionMap,
        //里面的键就是链接URL,值就是存在什么条件才能访问该链接(正式环境从数据库获取)
        Map<String, SysMenuRole> menuRoleMap = MenuRoleCache.menuRoleCacheMap;
        for (String key : menuRoleMap.keySet()) {
        	filterChainDefinitionMap.put(key, "jwt, roles["+menuRoleMap.get(key).getRoleNames()+"]");
        	System.out.println("key=roles["+menuRoleMap.get(key).getRoleNames()+"]");
		}
        
        // 所有url都必须认证通过才可以访问,必须放在最后
//        filterChainDefinitionMap.put("/**", "jwt, roles");
        filterChainDefinitionMap.put("/**", "jwt");
        // ========== 动态加载权限核心部分结束 ==========

        // 设置 Shiro 拦截器链
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        
        return shiroFilterFactoryBean;
    }
    
	/**
     * <h5>功能:禁用Session,不保存用户登录状态</h5>
     * 
     * @param securityManager
     * @return 
     */
//    @Bean
//    protected SessionStorageEvaluator sessionStorageEvaluator(){
//        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
//        sessionStorageEvaluator.setSessionStorageEnabled(false);
//        return sessionStorageEvaluator;
//    }

//	/**
//	 * <h5>功能:使用CGLIB代理来创建代理类,而不是使用默认的JDK代理,按需使用</h5> 
//	 * 强制使用cglib，防止重复代理和可能引起代理出错的问题 https://zhuanlan.zhihu.com/p/29161098
//	 * 
//	 * @param securityManager
//	 * @return
//	 */
//	@Bean
//	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
//		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
//		autoProxyCreator.setProxyTargetClass(true);
//		return autoProxyCreator;
//	}
}
